package com.unionPay.utils;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

public class Pin {
	public static String encryptedPin(String clrPin, String sPan,
			String sPublicKey) throws Exception {

		String encPin = null;
		/** 验证密码是否为空 **/
		if (null == clrPin || "".equals(clrPin.trim())) {
			return null;
		}
		/** 验证卡号是否为空 **/
		if (null == sPan || "".equals(sPan.trim())) {
			return null;
		}
		try {
			/** 生成PIN Block **/
			byte[] pinBlock = pin2PinBlockWithCardNO(clrPin, sPan);

			// 取得公钥
			X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64Class
					.decode(sPublicKey, 0));
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			// 生成公钥
			PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
			byte[] data = encryptedPin(publicKey, pinBlock);

			/** 使用Bsse64编码 **/
			byte[] raw = encode(data);
			encPin = new String(raw);
		} catch (Exception e) {

			throw new Exception("加密转PIN失败", e);
		}
		// ggl add
		String tempstr = "";
		for (int i = 0; i < encPin.toCharArray().length; i++) {
			if (encPin.charAt(i) != '\r' && encPin.charAt(i) != '\n') {
				tempstr += encPin.charAt(i);
			}
		}
		return tempstr;
		// ggl end
	}

	private static byte[] encryptedPin(PublicKey publicKey, byte[] plainPin) {
		byte[] raw = null;
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			int blockSize = cipher.getBlockSize();
			int outputSize = cipher.getOutputSize(plainPin.length);
			int leavedSize = plainPin.length % blockSize;
			int blocksSize = leavedSize != 0 ? plainPin.length / blockSize + 1
					: plainPin.length / blockSize;
			raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (plainPin.length - i * blockSize > 0) {
				if (plainPin.length - i * blockSize > blockSize)
					cipher.doFinal(plainPin, i * blockSize, blockSize, raw, i
							* outputSize);
				else
					cipher.doFinal(plainPin, i * blockSize, plainPin.length - i
							* blockSize, raw, i * outputSize);
				i++;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return raw;
	}

	/**
	 * 生成PIN BLOCK
	 */
	private static byte[] pin2PinBlockWithCardNO(String aPin, String aCardNO) {
		byte[] tPinByte = pin2PinBlock(aPin);
		if (aCardNO.length() == 11) {
			aCardNO = "00" + aCardNO;
		} else if (aCardNO.length() == 12) {
			aCardNO = "0" + aCardNO;
		}
		// 格式化卡�?
		byte[] tPanByte = formatPan(aCardNO);
		byte[] tByte = new byte[8];
		for (int i = 0; i < 8; i++) {
			tByte[i] = (byte) (tPinByte[i] ^ tPanByte[i]);
		}
		return tByte;
	}

	/**
	 * 格式化卡�?
	 */
	private static byte[] formatPan(String aPan) {
		int tPanLen = aPan.length();
		byte[] tByte = new byte[8];
		;
		int temp = tPanLen - 13;
		try {
			tByte[0] = (byte) 0x00;
			tByte[1] = (byte) 0x00;
			for (int i = 2; i < 8; i++) {
				String a = aPan.substring(temp, temp + 2);
				tByte[i] = (byte) Integer.parseInt(a, 16);
				temp = temp + 2;
			}
		} catch (Exception e) {
		}
		return tByte;
	}

	/**
	 * BASE64编码
	 */
	private static byte[] encode(byte[] inputByte) throws IOException {
		return Base64Class.encode(inputByte, 0);
	}

	public static byte[] pin2PinBlock(String aPin) {
		int tTemp = 1;
		int tPinLen = aPin.length();
		byte[] tByte = new byte[8];
		try {
			/*******************************************************************
			 * if (tPinLen > 9) { tByte[0] = (byte) Integer.parseInt(new
			 * Integer(tPinLen) .toString(), 16); } else { tByte[0] = (byte)
			 * Integer.parseInt(new Integer(tPinLen) .toString(), 10); }
			 ******************************************************************/
			tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen).toString(),
					10);
			if (tPinLen % 2 == 0) {
				for (int i = 0; i < tPinLen;) {
					String a = aPin.substring(i, i + 2);
					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
					if (i == (tPinLen - 2)) {
						if (tTemp < 7) {
							for (int x = (tTemp + 1); x < 8; x++) {
								tByte[x] = (byte) 0xff;
							}
						}
					}
					tTemp++;
					i = i + 2;
				}
			} else {
				for (int i = 0; i < tPinLen - 1;) {
					String a;
					a = aPin.substring(i, i + 2);
					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
					if (i == (tPinLen - 3)) {
						String b = aPin.substring(tPinLen - 1) + "F";
						tByte[tTemp + 1] = (byte) Integer.parseInt(b, 16);
						if ((tTemp + 1) < 7) {
							for (int x = (tTemp + 2); x < 8; x++) {
								tByte[x] = (byte) 0xff;
							}
						}
					}
					tTemp++;
					i = i + 2;
				}
			}
		} catch (Exception e) {
		}
		return tByte;
	}
}
